<?php
// +----------------------------------------------------------------------
// | ThinkBLOG (Build on ThinkPHP)
// +----------------------------------------------------------------------
// | @link ( http://www.yurnero.net )
// +----------------------------------------------------------------------
// | @licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | @author nicholas <nicholasinlove@126.com>
// +----------------------------------------------------------------------
// | $Id: Validate.class.php 145 2012-04-27 09:26:00Z nicholasinlove1986@gmail.com $
// +----------------------------------------------------------------------


//(copy Typecho
class Validate {
	
	/**
	 * 内部数据
	 *
	 * @access private
	 * @var array
	 */
	private $_data;
	
	/**
	 * 当前验证指针
	 *
	 * @access private
	 * @var string
	 */
	private $_key;
	
	/**
	 * 验证规则数组
	 *
	 * @access private
	 * @var array
	 */
	private $_rules = array ();
	
	/**
	 * 中断模式,一旦出现验证错误即抛出而不再继续执行
	 *
	 * @access private
	 * @var boolean
	 */
	private $_break = false;
	
	/**
	 * 增加验证规则
	 *
	 * @access public
	 * @param string $key 数值键值
	 * @param string $rule 规则名称
	 * @param string $message 错误字符串
	 * @return Typecho_Validation
	 */
	public function addRule($key, $rule, $message) {
		if (func_num_args () <= 3) {
			$this->_rules [$key] [] = array ($rule, $message );
		} else {
			$params = func_get_args ();
			$params = array_splice ( $params, 3 );
			$this->_rules [$key] [] = array_merge ( array ($rule, $message ), $params );
		}
		
		return $this;
	}
	
	/**
	 * 设置为中断模式
	 *
	 * @access public
	 * @return void
	 */
	public function setBreak() {
		$this->_break = true;
	}
	
	/**
	 * Run the Validator
	 * This function does all the work.
	 *
	 * @access	public
	 * @param   array $data 需要验证的数据
	 * @param   array $rules 验证数据遵循的规则
	 * @return	array
	 * @throws  Typecho_Validate_Exception
	 */
	public function run(array $data, $rules = NULL) {
		$result = array ();
		$this->_data = $data;
		$rules = empty ( $rules ) ? $this->_rules : $rules;
		
		// Cycle through the rules and test for errors
		foreach ( $rules as $key => $rules ) {
			$this->_key = $key;
			$data [$key] = (0 == strlen ( $data [$key] )) ? NULL : $data [$key];
			
			foreach ( $rules as $params ) {
				$method = $params [0];
				
				if ('required' != $method && 'confirm' != $method && 0 == strlen ( $data [$key] )) {
					continue;
				}
				
				$message = $params [1];
				$params [1] = $data [$key];
				$params = array_slice ( $params, 1 );
				
				if (! call_user_func_array ( is_array ( $method ) ? $method : array ($this, $method ), $params )) {
					$result [$key] = $message;
					break;
				}
			}
			
			/** 开启中断 */
			if ($this->_break && $result) {
				break;
			}
		}
		
		return $result;
	}
	
	/**
	 * 最小长度
	 *
	 * @access public
	 * @param string $str 待处理的字符串
	 * @param integer $length 最小长度
	 * @return boolean
	 */
	public function minLength($str, $length) {
		return (tstrlen ( $str ) >= $length);
	}
	
	/**
	 * 验证输入是否一致
	 *
	 * @access public
	 * @param string $str 待处理的字符串
	 * @param string $key 需要一致性检查的键值
	 * @return boolean
	 */
	public function confirm($str, $key) {
		return ! empty ( $this->_data [$key] ) ? ($str == $this->_data [$key]) : empty ( $str );
	}
	
	/**
	 * 是否为空
	 *
	 * @access public
	 * @param string $str 待处理的字符串
	 * @return boolean
	 */
	public function required($str) {
		return ! empty ( $this->_data [$this->_key] );
	}
	
	/**
	 * 枚举类型判断
	 *
	 * @access public
	 * @param string $str 待处理的字符串
	 * @param array $params 枚举值
	 * @return unknown
	 */
	public function enum($str, array $params) {
		return in_array ( $str, $params );
	}
	
	/**
	 * Max Length
	 *
	 * @access public
	 * @param string
	 * @return boolean
	 */
	public function maxLength($str, $length) {
		return (tstrlen ( $str ) < $length);
	}
	
	/**
	 * Valid Email
	 *
	 * @access public
	 * @param string
	 * @return boolean
	 */
	public function email($str) {
		return preg_match ( "/^[^@\s<&>]+@([-a-z0-9]+\.)+[a-z]{2,}$/i", $str );
	}
	
	/**
	 * 验证是否为网址
	 *
	 * @access public
	 * @param string $str
	 * @return boolean
	 */
	public function url($str) {
		$parts = @parse_url ( $str );
		if (! $parts) {
			return false;
		}
		
		return isset ( $parts ['scheme'] ) && in_array ( $parts ['scheme'], array ('http', 'https', 'ftp' ) ) && ! preg_match ( '/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', $str );
	}
	
	/**
	 * Alpha
	 *
	 * @access public
	 * @param string
	 * @return boolean
	 */
	public function alpha($str) {
		return preg_match ( "/^([a-z])+$/i", $str ) ? true : false;
	}
	
	/**
	 * Alpha-numeric
	 *
	 * @access public
	 * @param string
	 * @return boolean
	 */
	public function alphaNumeric($str) {
		return preg_match ( "/^([a-z0-9])+$/i", $str );
	}
	
	/**
	 * Alpha-numeric with underscores and dashes
	 *
	 * @access public
	 * @param string
	 * @return boolean
	 */
	public function alphaDash($str) {
		return preg_match ( "/^([_a-z0-9-])+$/i", $str ) ? true : false;
	}
	
	/**
	 * 对xss字符串的检测
	 *
	 * @access public
	 * @param string $str
	 * @return boolean
	 */
	public function xssCheck($str) {
		$search = 'abcdefghijklmnopqrstuvwxyz';
		$search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
		$search .= '1234567890!@#$%^&*()';
		$search .= '~`";:?+/={}[]-_|\'\\';
		
		for($i = 0; $i < strlen ( $search ); $i ++) {
			// ;? matches the ;, which is optional
			// 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
			

			// &#x0040 @ search for the hex values
			$str = preg_replace ( '/(&#[xX]0{0,8}' . dechex ( ord ( $search [$i] ) ) . ';?)/i', $search [$i], $str ); // with a ;
			// &#00064 @ 0{0,7} matches '0' zero to seven times
			$str = preg_replace ( '/(&#0{0,8}' . ord ( $search [$i] ) . ';?)/', $search [$i], $str ); // with a ;
		}
		
		return ! preg_match ( '/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', $str );
	}
	
	/**
	 * Numeric
	 *
	 * @access public
	 * @param integer
	 * @return boolean
	 */
	public function isFloat($str) {
		return ereg ( "^[0-9\.]+$", $str );
	}
	
	/**
	 * Is Numeric
	 *
	 * @access public
	 * @param string
	 * @return boolean
	 */
	public function isInteger($str) {
		return is_numeric ( $str );
	}
	
	/**
	 * 验证是否为网址
	 *
	 * @access public
	 * @param  string      $url      需要验证的网址
	 * @return boolean
	 */
	static public function checkUrl($url) {
		$parts = @parse_url ( $url );
		if (! $parts) {
			return false;
		}
		return isset ( $parts ['scheme'] ) && in_array ( $parts ['scheme'], array ('http', 'https', 'ftp' ) ) && ! preg_match ( '/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', $url );
	}
	
	/**
	 * 验证输入的邮件地址是否合法
	 *
	 * @access public
	 * @param  string      $email      需要验证的邮件地址
	 * @return bool
	 */
	static public function checkEmail($email) {
		$chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
		if (strpos ( $email, '@' ) !== false && strpos ( $email, '.' ) !== false) {
			if (preg_match ( $chars, $email )) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	/**
	 * 验证输入的用户名是否合法
	 *
	 * @access public
	 * @param  string      $username      需要验证的用户名
	 * @return bool
	 */
	static public function checkUsername($username) {
		$guestexp = '\xA1\xA1|\xAC\xA3|^Guest|^\xD3\xCE\xBF\xCD|\xB9\x43\xAB\xC8';
		$len = strlen ( $username );
		if ($len > 15 || $len < 3 || preg_match ( "/\s+|^c:\\con\\con|[%,\*\"\s\<\>\&]|$guestexp/is", $username )) {
			return false;
		} else {
			return true;
		}
	}
	
	/**
	 * 验证用户密码
	 *
	 * @access public
	 * @param  array   $password $hash
	 * @return void
	 */
	static public function checkPassword($password, $hash) {
		global $tb_hasher;
		if (empty ( $tb_hasher )) {
			import ( '@.ORG.Phpass' );
			$tb_hasher = new PasswordHash ( 8, true );
		}
		$check = $tb_hasher->CheckPassword ( $password, $hash );
		return $check;
	}
	
	/**
	 * 编译密码函数
	 *
	 * @access public
	 * @param  array   $password
	 * @return void
	 */
	static public function compilePassword($password) {
		global $tb_hasher;
		if (empty ( $tb_hasher )) {
			import ( '@.ORG.Phpass' );
			$tb_hasher = new PasswordHash ( 8, true );
		}
		return $tb_hasher->HashPassword ( $password );
	}

}